HAL SAI initialization and configuration functions migration

The goal of this page is to show how to migrate the Init sequence using STM32CubeMX2:

  • Open STM32CubeMX2 SAI configuration panel

  • Configure the SAI main features

  • Configure the advanced SAI features.

  • Configure the SAI GPIO PINS

  • Configure the SAI DMA(s) if the application requires to use the SAI in DMA mode.

  • Configure the NVIC if the application requires the SAI to be used in IT mode.

  • Generate the code

HAL SAI configuration panel

Create a new project with the STM32CubeMX2, then start the initialization and the main configuration.

Project configuration panel

HAL SAI main features configuration

Configure the SAI main features.

SAI main feature configuration

HAL SAI advanced features configuration

Configure the advanced SAI features.

SAI advanced feature configuration

GPIO configuration

Configure the SAI1_MCLK_A, SAI1_SD_A, SAI1_SCK_A, SAI1_FS_A, SAI1_D1, SAI1_D2, SAI1_D3, SAI1_CK1 and SAI1_CK2 pins.

SAI GPIO configuration

DMA configuration

Configure the DMA RX channel when the Audio mode is Master Receiver or Slave Receiver, and configure the DMA TX channel when the Audio mode is Master Transmitter or Slave Transmitter.

SAI DMA configuration

NVIC configuration

Configure the NVIC in case of an interrupt.

SAI NVIC configuration

Generated SAI initialization and de-initialization sequences

The SAI initialization sequence is generated in the mx_sai1_a_init and mx_sai1_b_init functions in mx_sai1.c file under $YOUR_PROJECT_NAME$/$YOUR_PROJECT_NAME$_SW/generated/STM32Cube_CodeGen.

Note

In HAL2, the PDM parameters is only available for SAI1 block A and is supported in master receiver mode.

As the hardware may vary, this will naturally have an impact on the RCC clock, pin and NVIC interrupt line used by the application.

STM32CubeMX2 Generated : SAI initialization and de-initialization sequences

Topic

HAL1 code snippet

HAL2 code snippet

Declaration of the handle

GPIO_InitTypeDef GPIO_InitStruct;
SAI_HandleTypeDef hsai_BlockA1;
SAI_HandleTypeDef hsai_BlockB1;
hal_gpio_config_t  gpio_config;
hal_sai_config_t sai_config;
hal_sai_pdm_mic_delay_t pdm_mic_delay;
hal_sai_handle_t hSAI1_A;
hal_sai_handle_t hSAI1_B;

Initialization and configuration sequence

static void MX_SAI1_Init(void)
{

  hsai_BlockA1.Instance = SAI1_Block_A;
  hsai_BlockA1.Init.Protocol = SAI_FREE_PROTOCOL;
  hsai_BlockA1.Init.AudioMode = SAI_MODEMASTER_RX;
  hsai_BlockA1.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_8K;
  hsai_BlockA1.Init.DataSize = SAI_DATASIZE_8;
  hsai_BlockA1.Init.FirstBit = SAI_FIRSTBIT_MSB;
  hsai_BlockA1.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE;
  hsai_BlockA1.FrameInit.FrameLength = 8;
  hsai_BlockA1.FrameInit.ActiveFrameLength = 1;
  hsai_BlockA1.FrameInit.FSDefinition = SAI_FS_STARTFRAME;
  hsai_BlockA1.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
  hsai_BlockA1.FrameInit.FSOffset = SAI_FS_FIRSTBIT;
  hsai_BlockA1.SlotInit.FirstBitOffset = 0;
  hsai_BlockA1.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;
  hsai_BlockA1.SlotInit.SlotNumber = 1;
  hsai_BlockA1.SlotInit.SlotActive = 0x00000000;

  hsai_BlockA1.Init.Synchro = SAI_SYNCHRONOUS;
  hsai_BlockA1.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE;
  hsai_BlockA1.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_EMPTY;
  hsai_BlockA1.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
  hsai_BlockA1.Init.MckOutput = SAI_MCK_OUTPUT_ENABLE;
  hsai_BlockA1.Init.MonoStereoMode = SAI_STEREOMODE;
  hsai_BlockA1.Init.CompandingMode = SAI_NOCOMPANDING;
  hsai_BlockA1.Init.TriState = SAI_OUTPUT_NOTRELEASED;
  hsai_BlockA1.Init.PdmInit.Activation = DISABLE;
  hsai_BlockA1.Init.PdmInit.MicPairsNbr = 1;
  hsai_BlockA1.Init.PdmInit.ClockEnable = SAI_PDM_CLOCK1_ENABLE;


  if (HAL_SAI_Init(&hsai_BlockA1) != HAL_OK)
  {
    Error_Handler();
  }

  hsai_BlockB1.Instance = SAI1_Block_B;
  hsai_BlockB1.Init.AudioMode = SAI_MODEMASTER_TX;
  hsai_BlockB1.Init.Synchro = SAI_ASYNCHRONOUS;
  hsai_BlockB1.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE;
  hsai_BlockB1.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
  hsai_BlockB1.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_EMPTY;
  hsai_BlockB1.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_192K;
  hsai_BlockB1.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
  hsai_BlockB1.Init.MckOutput = SAI_MCK_OUTPUT_DISABLE;
  hsai_BlockB1.Init.MonoStereoMode = SAI_STEREOMODE;
  hsai_BlockB1.Init.CompandingMode = SAI_NOCOMPANDING;
  hsai_BlockB1.Init.TriState = SAI_OUTPUT_NOTRELEASED;
  if (HAL_SAI_InitProtocol(&hsai_BlockB1,
                           SAI_I2S_STANDARD,
                           SAI_PROTOCOL_DATASIZE_16BIT,
                           2) != HAL_OK)
  {
    Error_Handler();
  }

}

void HAL_SAI_MspInit(SAI_HandleTypeDef* hsai)
{

  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  uint32_t SAI1_client =0;
  /* SAI1 */
    if(hsai->Instance==SAI1_Block_A)
    {
    /* Peripheral clock enable */

  /** Initializes the peripherals clock
  */
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SAI1;
    PeriphClkInit.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLL1;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
      Error_Handler();
    }

    if (SAI1_client == 0)
    {
       __HAL_RCC_SAI1_CLK_ENABLE();
    }
    SAI1_client ++;

    /**SAI1_A_Block_A GPIO Configuration
    PD6     ------> SAI1_SD_A
    PE4     ------> SAI1_FS_A
    PE5     ------> SAI1_SCK_A
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF13_SAI1;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF13_SAI1;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);







































    if(hsai->Instance==SAI1_Block_B)
    {
      /* Peripheral clock enable */

  /** Initializes the peripherals clock
  */
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SAI1;
    PeriphClkInit.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLL1;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
      Error_Handler();
    }

      if (SAI1_client == 0)
      {
       __HAL_RCC_SAI1_CLK_ENABLE();
      }
    SAI1_client ++;



















    /**SAI1_B_Block_B GPIO Configuration
    PB5     ------> SAI1_SD_B
    PF8     ------> SAI1_SCK_B
    PF7     ------> SAI1_MCLK_B
    PF9     ------> SAI1_FS_B
    */
    GPIO_InitStruct.Pin = GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF13_SAI1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_7|GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF13_SAI1;
    HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);

    }
}


static void MX_GPIO_Init(void)
{
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();

}
hal_sai_handle_t *mx_sai1_a_init(void)
{

  if (HAL_SAI_Init(&hSAI1_A, HAL_SAI1_A) != HAL_OK)
  {
    return NULL;
  }

  HAL_RCC_SAI1_EnableClock();

  if (HAL_RCC_SAI1_SetKernelClkSource(HAL_RCC_SAI1_CLK_SRC_PLL1R) != HAL_OK)
    {
      return NULL;
    }

  sai_config.protocol            = HAL_SAI_PROTOCOL_FREE;
  sai_config.mode                = HAL_SAI_MODE_MASTER_RX;
  sai_config.audio_frequency     = HAL_SAI_AUDIO_FREQUENCY_8KHZ;
  sai_config.mclk_oversampling   = HAL_SAI_MCLK_OVERSAMPLING_DISABLE;
  sai_config.data_size           = HAL_SAI_DATA_SIZE_8BITS;
  sai_config.bit_order           = HAL_SAI_BIT_ORDER_MSB;
  sai_config.clock_strobing_edge = HAL_SAI_CLOCK_STROBING_FALLING_EDGE;
  sai_config.frame.frame_length        = 8;
  sai_config.frame.active_frame_length = 1;
  sai_config.frame.fs_definition       = HAL_SAI_FS_START_FRAME;
  sai_config.frame.fs_polarity         = HAL_SAI_FS_POLARITY_FALLING;
  sai_config.frame.fs_offset           = HAL_SAI_FS_FIRST_BIT;
  sai_config.slot.slot_first_bit_offset = 0;
  sai_config.slot.slot_size             = HAL_SAI_SLOT_SIZE_DATA_SIZE;
  sai_config.slot.slot_number           = 1;
  sai_config.slot.slot_active           = HAL_SAI_SLOT_ACTIVE_0;

  if (HAL_SAI_SetConfig(&hSAI1_A, &sai_config) != HAL_OK)
  {
    return NULL;
  }

  if (HAL_SAI_SetSyncOutput(&hSAI1_A,
                            HAL_SAI_SYNC_OUTPUT_BLOCK_A_ENABLE) != HAL_OK)
  {
    return NULL;
  }

  if (HAL_SAI_SetCompanding(&hSAI1_A,
                            HAL_SAI_COMPANDING_ALAW_2CPL) != HAL_OK)
  {
    return NULL;
  }

  if (HAL_SAI_SetFifoThreshold(&hSAI1_A,
                               HAL_SAI_FIFO_THRESHOLD_FULL) != HAL_OK)
  {
    return NULL;
  }

  if (HAL_SAI_EnableMclkOutput(&hSAI1_A) != HAL_OK)
  {
    return NULL;
  }

  if (HAL_SAI_EnableOutputDrive(&hSAI1_A) != HAL_OK)
  {
    return NULL;
  }

  if (HAL_SAI_EnableTristateSDOutput(&hSAI1_A) != HAL_OK)
  {
    return NULL;
  }

  if (HAL_SAI_EnableMonoMode(&hSAI1_A) != HAL_OK)
  {
    return NULL;
  }

  if (HAL_SAI_EnablePdm(&hSAI1_A,
                        3,
                        HAL_SAI_PDM_CLOCK1_CLOCK2_ENABLE) != HAL_OK)
  {
    return NULL;
  }

  pdm_mic_delay.pdm_mic_pairs_nbr = 3;
  pdm_mic_delay.pdm_left_delay    = 0;
  pdm_mic_delay.pdm_right_delay   = 0;

  if (HAL_SAI_SetPdmMicDelay(&hSAI1_A,
                             &pdm_mic_delay) != HAL_OK)
  {
    return NULL;
  }

  HAL_RCC_GPIOB_EnableClock();

  HAL_RCC_GPIOD_EnableClock();

  HAL_RCC_GPIOE_EnableClock();

  HAL_RCC_GPIOA_EnableClock();


   /** SAI1_A GPIO Configuration
        PB2     ------>   SAI1_SD_A
        PE4     ------>   SAI1_FS_A
        PD6     ------>   SAI1_SCK_A
   */

   gpio_config.mode        = HAL_GPIO_MODE_ALTERNATE;
   gpio_config.output_type = HAL_GPIO_OUTPUT_PUSHPULL;
   gpio_config.pull        = HAL_GPIO_PULL_UP;
   gpio_config.speed       = HAL_GPIO_SPEED_FREQ_VERY_HIGH;
   gpio_config.alternate   = HAL_GPIO_AF_6;
   HAL_GPIO_Init(HAL_GPIOB, HAL_GPIO_PIN_2, &gpio_config);

   gpio_config.mode        = HAL_GPIO_MODE_ALTERNATE;
   gpio_config.output_type = HAL_GPIO_OUTPUT_PUSHPULL;
   gpio_config.pull        = HAL_GPIO_PULL_UP;
   gpio_config.speed       = HAL_GPIO_SPEED_FREQ_VERY_HIGH;
   gpio_config.alternate   = HAL_GPIO_AF_6;
   HAL_GPIO_Init(HAL_GPIOD, HAL_GPIO_PIN_6, &gpio_config);

   gpio_config.mode        = HAL_GPIO_MODE_ALTERNATE;
   gpio_config.output_type = HAL_GPIO_OUTPUT_PUSHPULL;
   gpio_config.pull        = HAL_GPIO_PULL_UP;
   gpio_config.speed       = HAL_GPIO_SPEED_FREQ_VERY_HIGH;
   gpio_config.alternate   = HAL_GPIO_AF_6;
   HAL_GPIO_Init(HAL_GPIOE, HAL_GPIO_PIN_4 , &gpio_config);

  return &hSAI1_A;
}


hal_sai_handle_t *mx_sai1_a_gethandle(void)
{
  return &hSAI1_A;
}




hal_sai_handle_t *mx_sai1_b_init(void)
{
  hal_sai_config_t sai_config;

  if (HAL_SAI_Init(&hSAI1_B, HAL_SAI1_B) != HAL_OK)
  {
    return NULL;
  }

  HAL_RCC_SAI1_EnableClock();

  if (HAL_RCC_SAI1_SetKernelClkSource(HAL_RCC_SAI1_CLK_SRC_PLL1R) != HAL_OK)
    {
      return NULL;
    }

  sai_config.mode                = HAL_SAI_MODE_MASTER_TX;
  sai_config.audio_frequency     = HAL_SAI_AUDIO_FREQUENCY_8KHZ;
  sai_config.mclk_oversampling   = HAL_SAI_MCLK_OVERSAMPLING_DISABLE;
  sai_config.protocol            = HAL_SAI_PROTOCOL_FREE;
  sai_config.data_size           = HAL_SAI_DATA_SIZE_8BITS;
  sai_config.bit_order           = HAL_SAI_BIT_ORDER_MSB;
  sai_config.clock_strobing_edge = HAL_SAI_CLOCK_STROBING_FALLING_EDGE;
  sai_config.slot.slot_first_bit_offset = 0;
  sai_config.slot.slot_size             = HAL_SAI_SLOT_SIZE_DATA_SIZE;
  sai_config.slot.slot_number           = 2;
  sai_config.slot.slot_active           = (HAL_SAI_SLOT_ACTIVE_0);
  sai_config.frame.frame_length        = 16;
  sai_config.frame.active_frame_length = 8;
  sai_config.frame.fs_definition       = HAL_SAI_FS_START_FRAME;
  sai_config.frame.fs_polarity         = HAL_SAI_FS_POLARITY_FALLING;
  sai_config.frame.fs_offset           = HAL_SAI_FS_FIRST_BIT;

  if (HAL_SAI_SetConfig(&hSAI1_B, &sai_config) != HAL_OK)
  {
    return NULL;
  }

  HAL_RCC_GPIOE_EnableClock();

  HAL_RCC_GPIOA_EnableClock();

  /** SAI1_B GPIO Configuration

      PE3     ------>   SAI1_SD_B
      PA8     ------>   SAI1_SCK_B
      PA7     ------>   SAI1_FS_B
  */
  gpio_config.mode        = HAL_GPIO_MODE_ALTERNATE;
  gpio_config.output_type = HAL_GPIO_OUTPUT_PUSHPULL;
  gpio_config.pull        = HAL_GPIO_PULL_UP;
  gpio_config.speed       = HAL_GPIO_SPEED_FREQ_VERY_HIGH;
  gpio_config.alternate   = HAL_GPIO_AF_6;
  HAL_GPIO_Init(HAL_GPIOE, HAL_GPIO_PIN_3, &gpio_config);

  gpio_config.mode        = HAL_GPIO_MODE_ALTERNATE;
  gpio_config.output_type = HAL_GPIO_OUTPUT_PUSHPULL;
  gpio_config.pull        = HAL_GPIO_PULL_UP;
  gpio_config.speed       = HAL_GPIO_SPEED_FREQ_VERY_HIGH;
  gpio_config.alternate   = HAL_GPIO_AF_6;
  HAL_GPIO_Init(HAL_GPIOA, HAL_GPIO_PIN_8 | HAL_GPIO_PIN_7, &gpio_config);

  return &hSAI1_B;
}

hal_sai_handle_t *mx_sai1_b_gethandle(void)
{
  return &hSAI1_B;
}

Deinitialization sequence

void HAL_SAI_MspDeInit(SAI_HandleTypeDef* hsai)
{
    /* SAI1 */
    if(hsai->Instance==SAI1_Block_A)
    {
    SAI1_client --;
    if (SAI1_client == 0)
      {
      /* Peripheral clock disable */
       __HAL_RCC_SAI1_CLK_DISABLE();
      }

    HAL_GPIO_DeInit(GPIOD, GPIO_PIN_6);

    HAL_GPIO_DeInit(GPIOE, GPIO_PIN_4|GPIO_PIN_5);

    }

    if(hsai->Instance==SAI1_Block_B)
    {
    SAI1_client --;
      if (SAI1_client == 0)
      {
      /* Peripheral clock disable */
      __HAL_RCC_SAI1_CLK_DISABLE();
      }

    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_5);

    HAL_GPIO_DeInit(GPIOF, GPIO_PIN_8|GPIO_PIN_7|GPIO_PIN_9);

    }
}
void mx_sai1_a_deinit(void)
{
  (void)HAL_SAI_DeInit(&hSAI1_A);

  HAL_RCC_SAI1_Reset();

  HAL_RCC_SAI1_DisableClock();

  /* De-initialize all GPIO pins associated with SAI1 */
  HAL_GPIO_DeInit(HAL_GPIOB, HAL_GPIO_PIN_2);

  HAL_GPIO_DeInit(HAL_GPIOD, HAL_GPIO_PIN_6);

  HAL_GPIO_DeInit(HAL_GPIOE, HAL_GPIO_PIN_4);

}


void mx_sai1_b_deinit(void)
{
  (void)HAL_SAI_DeInit(&hSAI1_B);

  HAL_RCC_SAI1_Reset();

  HAL_RCC_SAI1_DisableClock();

  /* De-initialize all GPIO pins associated with SAI1 */

  HAL_GPIO_DeInit(HAL_GPIOE, HAL_GPIO_PIN_3);

  HAL_GPIO_DeInit(HAL_GPIOA, HAL_GPIO_PIN_7 | HAL_GPIO_PIN_8);

}